﻿#include "FITKAcousticsVTKGraphObjectScalarBars.h"

// VTK
#include <vtkProperty.h>
#include <vtkProperty2D.h>
#include <vtkTextProperty.h>
#include <vtkLookupTable.h>
#include <vtkScalarBarActor.h>

// App
#include "FITK_Kernel/FITKAppFramework/FITKGlobalData.h"
#include "FITK_Kernel/FITKAppFramework/FITKAppFramework.h"

// Graph and filter
#include "FITKAcousticsVTKCommons.h"

namespace Exchange
{
    FITKAcousticsVTKGraphObjectScalarBars::FITKAcousticsVTKGraphObjectScalarBars()
        : FITKAcousticsVTKGraphObject3D()
    {
        // Nothing to do here.
    }

    FITKAcousticsVTKGraphObjectScalarBars::~FITKAcousticsVTKGraphObjectScalarBars()
    {

    }

    vtkScalarBarActor* FITKAcousticsVTKGraphObjectScalarBars::getScalarBarByPort(int port)
    {
        return m_barHash.value(port, nullptr);
    }

    void FITKAcousticsVTKGraphObjectScalarBars::setInfo(QString title, double min, double max, int port)
    {
        // Create the scalar bar.
        createScalarBar(port);

        vtkScalarBarActor* scalarBar = getScalarBarByPort(port);
        if (!scalarBar)
        {
            return;
        }

        // Set the title text.
        scalarBar->SetTitle(QStringToCharA(title));

        // Update the range.
        vtkLookupTable* lutBar = vtkLookupTable::SafeDownCast(scalarBar->GetLookupTable());
        if (lutBar)
        {
            lutBar->SetTableRange(min, max);
            lutBar->Build();
        }

        scalarBar->Modified();
    }

    void FITKAcousticsVTKGraphObjectScalarBars::setVisibleByPort(bool visibility, int port)
    {
        // Create the scalar bar.
        createScalarBar(port);

        vtkScalarBarActor* scalarBar = getScalarBarByPort(port);
        if (!scalarBar)
        {
            return;
        }

        scalarBar->SetVisibility(visibility);

        // Update the layout.
        updateScalarBarSizeAndPos();

        scalarBar->Modified();
    }

    void FITKAcousticsVTKGraphObjectScalarBars::setVisible(bool visibility)
    {
        this->Superclass::setVisible(visibility);

        // Update the layout.
        updateScalarBarSizeAndPos();
    }

    void FITKAcousticsVTKGraphObjectScalarBars::setEnableLogScale(bool isOn, int port)
    {
        // Create the scalar bar.
        createScalarBar(port);

        vtkScalarBarActor* scalarBar = getScalarBarByPort(port);
        if (!scalarBar)
        {
            return;
        }

        vtkLookupTable* lutBar = vtkLookupTable::SafeDownCast(scalarBar->GetLookupTable());
        if (!lutBar)
        {
            return;
        }

        lutBar->SetScale(isOn ? VTK_SCALE_LOG10 : VTK_SCALE_LINEAR);
        lutBar->Build();

        scalarBar->Modified();
    }

    void FITKAcousticsVTKGraphObjectScalarBars::createScalarBar(int port)
    {
        if (m_barHash.contains(m_port))
        {
            return;
        }

        // Initialize the scalar bar.
        vtkScalarBarActor* scalarBar = vtkScalarBarActor::New();
        scalarBar->SetVisibility(false);
        scalarBar->SetTitle("NONE");

        // Set the frame properties.
        // scalarBar->DrawFrameOn();
        // scalarBar->GetFrameProperty()->SetLineWidth(2);
        // scalarBar->GetFrameProperty()->SetOpacity(0.7);
        // scalarBar->GetFrameProperty()->SetColor(1.0, 1.0, 1.0);

        // Set the value format.
        scalarBar->SetLabelFormat("%-#.3e");

        // Set the lookup table.
        //@{
        int colorNum = 16;

        double colorAbove3[3]{ 0., 0., 0. };
        double colorBelow3[3]{ 0., 0., 0. };
        FITKAcousticsVTKCommons::QColorToDouble3(FITKAcousticsVTKCommons::s_postAboveColor, colorAbove3);
        FITKAcousticsVTKCommons::QColorToDouble3(FITKAcousticsVTKCommons::s_postBelowColor, colorBelow3);

        vtkSmartPointer<vtkLookupTable> lutBar = vtkSmartPointer<vtkLookupTable>::New();
        lutBar->SetUseAboveRangeColor(true);
        lutBar->SetUseBelowRangeColor(true);
        lutBar->SetAboveRangeColor(colorAbove3);
        lutBar->SetBelowRangeColor(colorBelow3);
        lutBar->SetNumberOfColors(colorNum);
        lutBar->SetHueRange(0.666667, 0);
        lutBar->SetSaturationRange(1, 1);
        lutBar->SetValueRange(1, 1);
        scalarBar->SetLookupTable(lutBar);
        //@}

        // Annotations at right. label at left.
        scalarBar->SetTextPositionToPrecedeScalarBar();

        // The text color.
        double textColor3[3]{ 0., 0., 0. };

        // Title font
        scalarBar->GetTitleTextProperty()->SetBold(false);
        scalarBar->GetTitleTextProperty()->SetItalic(false);
        scalarBar->GetTitleTextProperty()->SetFontSize(15);
        scalarBar->GetTitleTextProperty()->SetColor(textColor3);
        scalarBar->GetTitleTextProperty()->SetUseTightBoundingBox(true);
        scalarBar->GetTitleTextProperty()->SetJustificationToCentered();
        scalarBar->GetTitleTextProperty()->SetVerticalJustificationToTop();

        // Ticker labels font.
        scalarBar->GetLabelTextProperty()->SetBold(false);
        scalarBar->GetLabelTextProperty()->SetItalic(false);
        scalarBar->GetLabelTextProperty()->SetFontSize(14);
        scalarBar->GetLabelTextProperty()->SetColor(textColor3);

        scalarBar->SetUnconstrainedFontSize(true);
        scalarBar->SetVerticalTitleSeparation(8);
        scalarBar->SetTitleRatio(1);
        scalarBar->SetBarRatio(0.2);

        // Annotation text font.
        scalarBar->GetAnnotationTextProperty()->SetBold(false);
        scalarBar->GetAnnotationTextProperty()->SetItalic(false);
        scalarBar->GetAnnotationTextProperty()->SetFontSize(14);
        scalarBar->GetAnnotationTextProperty()->SetColor(textColor3);

        scalarBar->SetNumberOfLabels(colorNum);

        // Initialize the coordinate system.
        scalarBar->GetPositionCoordinate()->SetCoordinateSystemToNormalizedDisplay();       

        // Update the scalar bar's properties.
        scalarBar->Modified();

        addActor(scalarBar);

        //// Save the scalar bar with the port.
        //if (m_barHash.contains(port))
        //{
        //    while (m_barHash.contains(m_port))
        //    {
        //        m_port++;
        //    }

        //    m_barHash.insert(m_port, scalarBar);
        //}

        m_barHash.insert(port, scalarBar);
    }

    void FITKAcousticsVTKGraphObjectScalarBars::updateScalarBarSizeAndPos()
    {
        // The current count of the visible scalar bars.
        int visibleNum = 0;
        double width = 0.1;
        double height = 0.8;
        double margin = 0.05;

        for (vtkProp* prop : m_actorList)
        {
            vtkScalarBarActor* scalarBar = vtkScalarBarActor::SafeDownCast(prop);
            if (!scalarBar)
            {
                continue;
            }

            // Skip the invisible scalar bar.
            if (!scalarBar->GetVisibility())
            {
                continue;
            }

            visibleNum++;

            // Set fix size and postion.
            scalarBar->SetPosition2(width, height); // Size
            scalarBar->SetPosition(1. - width * visibleNum * 1.1 - margin, (1. - height) * 0.5); // Position

            scalarBar->Modified();
        }
    }
}   // namespace Exchange